/**
 * 项目名：五位一体化工安全信息平台
 * 日期：    2019-12-06 15:05:46
 * Copyright (c) 2015- joysuch-版权所有
 */

package com.joysuch.wwyt.bp.service.impl;

import com.alibaba.fastjson.JSONObject;
import com.joysuch.wwyt.bp.bean.*;
import com.joysuch.wwyt.bp.bean.safetyworkcert.BpWorkSafetyCertSearchBean;
import com.joysuch.wwyt.bp.entity.*;
import com.joysuch.wwyt.bp.entity.dsl.QBpWorkSafetyCert;
import com.joysuch.wwyt.bp.entity.inspect.BpInspectRecord;
import com.joysuch.wwyt.bp.enums.DataStateTypes;
import com.joysuch.wwyt.bp.enums.SafetyWorkStates;
import com.joysuch.wwyt.bp.enums.SafetyWorkTypes;
import com.joysuch.wwyt.bp.enums.WorkLevels;
import com.joysuch.wwyt.bp.repository.*;
import com.joysuch.wwyt.bp.service.BpWorkSafetyApplyFireService;
import com.joysuch.wwyt.bp.service.BpWorkSafetyAuditService;
import com.joysuch.wwyt.core.bean.SimpleSelectListBean;
import com.joysuch.wwyt.core.common.util.DateTimeUtil;
import com.joysuch.wwyt.core.common.util.PageDataUtils;
import com.joysuch.wwyt.core.common.util.PageDataUtils.PageDataConvert;
import com.joysuch.wwyt.core.common.util.SimpleDateFormatCache;
import com.joysuch.wwyt.core.entity.BaseUser;
import com.joysuch.wwyt.core.exception.BusinessRestrictionsException;
import com.joysuch.wwyt.core.repository.BaseUserDao;
import com.joysuch.wwyt.core.support.Context;
import com.joysuch.wwyt.risk.repository.RiskDistrictDao;
import com.joysuch.wwyt.risk.util.RiskPointUtil;
import com.querydsl.core.types.ExpressionUtils;
import com.querydsl.core.types.Predicate;
import io.swagger.annotations.ApiModelProperty;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.shiro.util.CollectionUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Root;
import javax.transaction.Transactional;
import java.lang.reflect.Array;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
import java.time.ZoneId;
import java.util.*;

@Service
@Transactional
public class BpWorkSafetyAuditServiceImpl implements BpWorkSafetyAuditService {

    @Autowired
    private BpWorkSafetyAuditDao dao;
    @Autowired
    private BpWorkSafetyApplyFireService fireService;
    @Autowired
    private BpWorkSafetyApplyFireDao fireDao;
    @Autowired
    private BpDepartDao departDao;
    @Autowired
    private BaseUserDao baseUserDao;
    @Autowired
    private RiskDistrictDao riskDistrictDao;
    @Autowired
    private BpWorkSafetyCertDao certDao;
    @Autowired
    private BpWorkSafetyAuditTemplateDao bpWorkSafetyAuditTemplateDao;
    @Autowired
    private BpWorkSafetyAuditProcessDao bpWorkSafetyAuditProcessDao;

    @Override
    public Page<BpWorkSafetyAuditListBean> findByPage(Pageable page, BpWorkSafetyAuditListSearchBean condition) {
        Predicate predicate = prepareListSearchCondition(condition);
        Page<BpWorkSafetyCert> data = predicate == null ? certDao.findAll(page) : certDao.findAll(predicate, page);

        return PageDataUtils.convertPageData(data, new PageDataConvert<BpWorkSafetyAuditListBean, BpWorkSafetyCert>() {
            @Override
            public BpWorkSafetyAuditListBean convert(BpWorkSafetyCert f) {
                BpWorkSafetyAuditListBean bean = new BpWorkSafetyAuditListBean();

                if (f.getState() == 1) {
                    //审核模板
                    List<BpWorkSafetyAuditTemplate> tList = new ArrayList<>();
                    if (f.getType() != null && f.getWorkLevel() == null) {
                        tList = bpWorkSafetyAuditTemplateDao.findByType(f.getType());
                    } else if (f.getType() != null && f.getWorkLevel() != null) {
                        tList = bpWorkSafetyAuditTemplateDao.findByTypeAndWorkLevel(f.getType(), f.getWorkLevel());
                    }
                    //审核流程
                    BpWorkSafetyAuditProcess process = bpWorkSafetyAuditProcessDao.findByCertId(f.getId());
                    if (process == null) {
                        //目前一个作业证只有一个审核模板
                        BpWorkSafetyAuditProcessAddBean aBean = JSONObject.parseObject(tList.get(0).getProcessJson(),
                                BpWorkSafetyAuditProcessAddBean.class);
                        List<BpWorkSafetyAuditProcessBean> processBeans = aBean.getProcessBeans();
                        if (!CollectionUtils.isEmpty(processBeans)) {
                            for (BpWorkSafetyAuditProcessBean pBean : processBeans) {
                                //类型是岗位
                                if (pBean.getType() == 0) {
                                    if (pBean.getPersonOrDepartId().equals(Context.getJobId())) {
                                        return getBpWorkSafetyAuditListBean(f, bean);
                                    }
                                } else if (pBean.getType() == 1) {
                                    if (pBean.getPersonOrDepartId().equals(Context.getCurrentUserId())) {
                                        return getBpWorkSafetyAuditListBean(f, bean);
                                    }
                                }
                            }
                        }

                    } else if (process.getNextAuditorId() != null) {
                        if (process.getNextAuditorType() == 0) {
                            if (process.getNextAuditorId().equals(Context.getJobId())) {
                                return getBpWorkSafetyAuditListBean(f, bean);
                            }
                        } else if (process.getNextAuditorType() == 1) {
                            if (process.getNextAuditorId().equals(Context.getCurrentUserId())) {
                                return getBpWorkSafetyAuditListBean(f, bean);
                            }
                        }
                    }
                }
                // ID
                bean.setId(f.getId());
                // 作业类型
                bean.setType(f.getType() + "安全作业");
                // 作业ID
                bean.setWorkId(f.getId());
                bean.setCode(f.getCode());
                completeApplyInfo(bean, f);
                // 状态
                bean.setState(f.getState());
                bean.setStateName(parseStateName(f.getState()));
                //
                bean.setTypeName(SafetyWorkTypes.findByName(f.getType()).getCode());
                bean.setWorkLevelName(WorkLevels.findNameById(f.getWorkLevel()));
                if ("动火".equals(f.getType()) && f.getWorkLevel() == 0) {
                    bean.setWorkLevelName("特殊危险");
                }
                if (f.getState() == SafetyWorkStates.AUDIT_SUCCESS.getId()) {
                    bean.setAuditResult("通过");
                } else {
                    bean.setAuditResult("");
                }
                bean.setStateName(SafetyWorkStates.findNameById(f.getState()));

                // 审核信息
                bean.setAuditMsg(f.getAuditMsg());
                if (f.getAuditUserId() != null) {
                    bean.setAuditUser(baseUserDao.getBaseUserNameById(f.getAuditUserId()));
                }
                bean.setJhaEvaluationId(f.getJhaEvaluationId());
                return bean;
            }
        });
    }

    private BpWorkSafetyAuditListBean getBpWorkSafetyAuditListBean(BpWorkSafetyCert f, BpWorkSafetyAuditListBean bean) {
        // ID
        bean.setId(f.getId());
        // 作业类型
        bean.setType(f.getType() + "安全作业");
        // 作业ID
        bean.setWorkId(f.getId());
        bean.setCode(f.getCode());
        completeApplyInfo(bean, f);
        // 状态
        bean.setState(f.getState());
        bean.setStateName(parseStateName(f.getState()));
        //
        bean.setTypeName(SafetyWorkTypes.findByName(f.getType()).getCode());
        bean.setWorkLevelName(WorkLevels.findNameById(f.getWorkLevel()));
        if ("动火".equals(f.getType()) && f.getWorkLevel() == 0) {
            bean.setWorkLevelName("特殊危险");
        }
        if (f.getState() == SafetyWorkStates.AUDIT_SUCCESS.getId()) {
            bean.setAuditResult("通过");
        } else {
            bean.setAuditResult("");
        }
        bean.setStateName(SafetyWorkStates.findNameById(f.getState()));

        // 审核信息
        bean.setAuditMsg(f.getAuditMsg());
        if (f.getAuditUserId() != null) {
            bean.setAuditUser(baseUserDao.getBaseUserNameById(f.getAuditUserId()));
        }
        bean.setJhaEvaluationId(f.getJhaEvaluationId());
        return bean;
    }

    protected void completeApplyInfo(BpWorkSafetyAuditListBean bean, BpWorkSafetyCert one) {
        bean.setApplyTime(SimpleDateFormatCache.getYmd().format(one.getApplyTime()));
        bean.setWorkTime(parseWorkTime(one));
        if (one.getApplyDepartId() != null) {
            bean.setApplyDepartName(departDao.findDepartNameById(one.getApplyDepartId()));
        }
        if (one.getApplyUserId() != null) {
            bean.setApplyUserName(baseUserDao.getBaseUserNameById(one.getApplyUserId()));
        }
        if (one.getRiskDistrictId() != null) {
            bean.setRiskDistrictName(riskDistrictDao.findNameById(one.getRiskDistrictId()));
        }

    }

    protected String parseWorkTime(BpWorkSafetyCert f) {
        return SimpleDateFormatCache.getYmdZC().format(f.getStartTime()) + " - "
                + SimpleDateFormatCache.getYmdZC().format(f.getEndTime());
    }

    protected String parseStateName(Integer state) {
        return SafetyWorkStates.findNameById(state);
    }

    private Predicate prepareListSearchCondition(BpWorkSafetyAuditListSearchBean condition) {
        QBpWorkSafetyCert audit = QBpWorkSafetyCert.bpWorkSafetyCert;
        Predicate p;
        if (condition.getState() != null) {
            p = audit.state.eq(condition.getState());
        } else {
            p = audit.state.in(1, 2, 3);
        }
        if (condition.getCodeOrLevel() != null) {
            Predicate p1 = audit.code.like("%" + condition.getCodeOrLevel() + "%");
            Integer level = RiskPointUtil.findWorkLevelFromText(condition.getCodeOrLevel());
            if (level != null) {
                p1 = ExpressionUtils.or(p1, audit.workLevel.eq(level));
            }
            p = ExpressionUtils.and(p, p1);
        }

        return p;
    }

    @Override
    public void delete(Long id) throws BusinessRestrictionsException {
        // 校验业务逻辑是否允许删除。如本数据被其他业务关联，删除后导致其他业务不可用。不能删除时将抛出业务异常
        checkBussinessRestrictions(id);
        dao.deleteById(id);
    }

    /**
     * 校验业务逻辑是否允许删除。如本数据被其他业务关联，删除后导致其他业务不可用
     *
     * @param id 要删除的业务ID
     * @throws //BussinessRestrictionsException 抛出的业务异常
     */
    private void checkBussinessRestrictions(Long id) throws BusinessRestrictionsException {

    }

    @Override
    public BpWorkSafetyAudit findById(Long id) {
        return dao.findById(id).get();
    }

    @Override
    public BpWorkSafetyAudit addOrUpdateWorkSafetyAudit(SafetyWorkTypes type, Long workId, String workCode,
                                                        Long opFireFirstAuditUserId) {
        BpWorkSafetyAudit entity = dao.findByTypeAndWorkId(type.getName(), workId);
        if (entity == null) {
            entity = new BpWorkSafetyAudit();
            entity.setType(type.getName());
            entity.setWorkId(workId);
            entity.setWorkCode(workCode);
        }
        // 将状态重新置为待申请
        entity.setState(0);
        entity.setOpFireFirstAuditUserId(opFireFirstAuditUserId);
        dao.save(entity);
        return entity;
    }

    @Override
    public void changeState(SafetyWorkTypes type, Long workId, Integer state, String msg) {
        BpWorkSafetyAudit audit = dao.findByTypeAndWorkId(type.getName(), workId);
        audit.setState(state);
        audit.setAuditTime(new Date());
        audit.setAuditUserId(Context.getCurrentUserId());
        audit.setAuditMsg(msg);
        dao.save(audit);

        // 更新相关业务单据
        if (type == SafetyWorkTypes.DONG_HUO) {
            updateDonghuoAuditMsg(audit);
        }
    }

    private void updateDonghuoAuditMsg(BpWorkSafetyAudit audit) {
        BpWorkSafetyApplyFire work = fireService.findById(audit.getWorkId());
        work.setState(audit.getState());
        work.setAuditMsg(audit.getAuditMsg());
        fireDao.save(work);
    }

    @Override
    public BpWorkSafetyAudit findByTypeAndWorkId(SafetyWorkTypes type, Long id) {
        return dao.findByTypeAndWorkId(type.getName(), id);
    }

    @Override
    public void changeCheckState(SafetyWorkTypes type, Long workId, Integer state, String msg) {
        BpWorkSafetyAudit audit = dao.findByTypeAndWorkId(type.getName(), workId);
        audit.setCheckMsg(msg);
        audit.setCheckState(state);
        audit.setCheckTime(new Date());
        audit.setCheckUserId(Context.getCurrentUserId());
        dao.save(audit);
    }

    @Override
    public Page<BpWorkSafetyAuditListBean> findByPageCheck(Pageable page, BpWorkSafetyAuditListSearchBean condition) {
        Predicate predicate = prepareCheckListSearchCondition(condition);

        Page<BpWorkSafetyCert> data = predicate == null ? certDao.findAll(page) : certDao.findAll(predicate, page);

        return PageDataUtils.convertPageData(data, new PageDataConvert<BpWorkSafetyAuditListBean, BpWorkSafetyCert>() {

            @Override
            public BpWorkSafetyAuditListBean convert(BpWorkSafetyCert f) {
                BpWorkSafetyAuditListBean bean = new BpWorkSafetyAuditListBean();

                // ID
                bean.setId(f.getId());
                // 作业类型
                bean.setType(f.getType() + "安全作业");
                // 作业ID
                bean.setWorkId(f.getId());
                // 作业证编号
                bean.setCode(f.getCode());
                bean.setWorkLevelName(WorkLevels.findNameById(f.getWorkLevel()));
                if ("动火".equals(f.getType()) && f.getWorkLevel() == 0) {
                    bean.setWorkLevelName("特殊危险");
                }
                completeApplyInfo(bean, f);
                // 状态
                if (f.getState() == SafetyWorkStates.CHECK_ACCEPTED.getId()) {
                    bean.setAuditResult("通过");
                } else {
                    bean.setAuditResult("");
                }
                bean.setState(f.getState());
                bean.setStateName(SafetyWorkStates.findNameById(f.getState()));

                bean.setTypeName(SafetyWorkTypes.findByName(f.getType()).getCode());

                // 审核信息
                bean.setAuditMsg(f.getAuditMsg());
                // 审核人
                if (f.getAuditUserId() != null) {
                    bean.setAuditUser(baseUserDao.getBaseUserNameById(f.getAuditUserId()));
                }
                return bean;
            }

        });
    }


    private Predicate prepareCheckListSearchCondition(BpWorkSafetyAuditListSearchBean condition) {
        QBpWorkSafetyCert audit = QBpWorkSafetyCert.bpWorkSafetyCert;
        Predicate p;
        if (condition.getState() != null) {
            p = audit.state.eq(condition.getState());
        } else {
            p = audit.state.in(2, 4, 5, 6);
        }
        if (condition.getCodeOrLevel() != null) {
            Integer level = RiskPointUtil.findWorkLevelFromText(condition.getCodeOrLevel());
            Predicate p2 = null;
            if (level == null) {
                p2 = audit.code.contains(condition.getCodeOrLevel());
            } else if (condition.getCodeOrLevel().contains("特级")) {
                // predicate = ExpressionUtils.and(predicate, q.state.eq(DataStateTypes.EFFECTIVE.getState()).or(q.state.isNull()));
                p2 = ExpressionUtils.or(audit.workLevel.eq(level), audit.code.contains(condition.getCodeOrLevel()));
                p2 = ExpressionUtils.and(p2, audit.type.eq("高处"));
            } else if (condition.getCodeOrLevel().contains("特殊") || condition.getCodeOrLevel().contains("特殊危险")) {
                p2 = ExpressionUtils.or(audit.workLevel.eq(level), audit.code.contains(condition.getCodeOrLevel()));
                p2 = ExpressionUtils.and(p2, audit.type.eq("动火"));
            } else {
                p2 = ExpressionUtils.or(audit.workLevel.eq(level), audit.code.contains(condition.getCodeOrLevel()));
            }
            p = ExpressionUtils.and(p, p2);
        }
        return p;
    }

    @Override
    public Page<BpWorkSafetyAuditListBean> findByPageAll(Pageable page, BpWorkSafetyAuditListSearchBean condition) {
        Predicate predicate = prepareAllSearchCondition(condition);

        Page<BpWorkSafetyCert> data = predicate == null ? certDao.findAll(page) : certDao.findAll(predicate, page);
        //查询申请列表只显示自己申请的

        Long currentUserId = Context.getCurrentUserId();
        Iterator<BpWorkSafetyCert> iterator = data.iterator();
        while (iterator.hasNext()) {
            BpWorkSafetyCert bpWorkSafetyCert = iterator.next();
            if (!currentUserId.equals(bpWorkSafetyCert.getCreateBy())) {
                iterator.remove();
            }
        }

        return PageDataUtils.convertPageData(data, new PageDataConvert<BpWorkSafetyAuditListBean, BpWorkSafetyCert>() {

            @Override
            public BpWorkSafetyAuditListBean convert(BpWorkSafetyCert f) {
                BpWorkSafetyAuditListBean bean = new BpWorkSafetyAuditListBean();

                // ID
                bean.setId(f.getId());
                // 作业类型
                bean.setType(f.getType() + "安全作业");
                // 作业ID
                bean.setWorkId(f.getId());
                // 作业证编号
                bean.setCode(f.getCode());
                bean.setWorkLevelName(WorkLevels.findNameById(f.getWorkLevel()));
                if ("动火".equals(f.getType()) && f.getWorkLevel() == 0) {
                    bean.setWorkLevelName("特殊危险");
                }
                completeApplyInfo(bean, f);
                // 状态
//                if (f.getState() == null || f.getState() == SafetyWorkStates.INITIAL.getId()) {
//                    bean.setAuditResult("待申请");
//                } else if (f.getState() == SafetyWorkStates.WAITING_FOR_AUDIT.getId()) {
//                    bean.setAuditResult("待审核");
//                } else if (f.getState() == SafetyWorkStates.AUDIT_SUCCESS.getId()) {
//                    bean.setAuditResult("审核通过");
//                } else if (f.getState() == SafetyWorkStates.AUDIT_FAILED.getId()) {
//                    bean.setAuditResult("审核未通过");
//                } else if (f.getState() == SafetyWorkStates.CHECK_ACCEPTED.getId()) {
//                    bean.setAuditResult("验收通过");
//                }
                bean.setAuditResult(SafetyWorkStates.findNameById(f.getState()));
                bean.setState(f.getState());
                bean.setStateName(SafetyWorkStates.findNameById(f.getState()));
                // 审核信息
                bean.setAuditMsg(f.getAuditMsg());
                if (f.getAuditUserId() != null) {
                    bean.setAuditUser(baseUserDao.getBaseUserNameById(f.getAuditUserId()));
                }
                bean.setTypeName(SafetyWorkTypes.findByName(f.getType()).getCode());

                // 审核信息
                bean.setAuditMsg(f.getAuditMsg());
                // 审核人
                if (f.getAuditUserId() != null) {
                    bean.setAuditUser(baseUserDao.getBaseUserNameById(f.getAuditUserId()));
                }
                return bean;
            }

        });
    }


    private Predicate prepareAllSearchCondition(BpWorkSafetyAuditListSearchBean condition) {
        QBpWorkSafetyCert audit = QBpWorkSafetyCert.bpWorkSafetyCert;
        Predicate p = null;
        if (condition.getState() != null) {
            p = audit.state.eq(condition.getState());
        }
        if (condition.getCodeOrLevel() != null) {
            Integer level = RiskPointUtil.findWorkLevelFromText(condition.getCodeOrLevel());
            Predicate p2 = null;
            if (level == null) {
                p2 = audit.code.contains(condition.getCodeOrLevel());
            } else {
                p2 = ExpressionUtils.or(audit.workLevel.eq(level), audit.code.contains(condition.getCodeOrLevel()));
            }
            p = ExpressionUtils.and(p, p2);
        }
        return p;
    }

}
